package com.koron.order.cockpit.service.impl;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.json.JSONUtil;
import com.github.pagehelper.PageHelper;
import com.koron.bean.base.Response;
import com.koron.bean.query.PageQuery;
import com.koron.bean.system.org.OrgBean;
import com.koron.common.core.business.datadict.bean.po.SysDataDict;
import com.koron.common.core.business.datadict.bean.po.SysDataDictDetail;
import com.koron.common.core.business.datadict.service.SysDataDictService;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.order.cockpit.bean.EquipmentStatus;
import com.koron.order.cockpit.mapper.YcCockpitMapper;
import com.koron.order.cockpit.service.YcCockpitService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.koron.ebs.mybatis.ADOConnection;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class YcCockpitServiceImpl implements YcCockpitService {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private SysDataDictService sysDataDictService;


    private final String REDIS_KEY = "cockpit:orgDept";
    private final int REDIS_EXPIRY_HOURS = 2;

    static Map<String, Long> defectMap = new HashMap<>();

    static {
        List<String> statusList = Arrays.asList("WAIT_REVIEW", "WAIT_DISPATCH", "WAIT_EXECUTE", "IN_EXECUTE", "WAIT_ACCEPT");
        statusList.stream().forEach(s -> {
            defectMap.computeIfAbsent(s, k -> 0L);
        });
    }


    @Override
    @TaskAnnotation("getDefectTypeAndCountByDate")
    public Response getDefectTypeAndCountByDate(SessionFactory factory, String date) {
        // 获取数据字典中配置的统计单位
        List<String> orgDept = getOrgs(factory);
        // 获取到对应单位下的所有部门
        Map<String, List<String>> deptMap = recursionGetOrgDept(factory, orgDept);
        List<CompletableFuture> futureList = new ArrayList<>();
        for (Map.Entry<String, List<String>> entry : deptMap.entrySet()) {
            try {
                TimeUnit.MILLISECONDS.sleep(100);
            } catch (InterruptedException e) {
                log.error(e.getMessage(), e);
            }
            CompletableFuture<Map<String, Object>> future = CompletableFuture.supplyAsync(() -> ADOConnection.runTask(ThreadLocalContext.get().getCurrDs(), sessionFactory->{
                YcCockpitMapper mapper1 = sessionFactory.getMapper(YcCockpitMapper.class);
                String name = entry.getKey();
                List<String> deptId = entry.getValue();
                Map<String, Object> map = mapper1.getDefectTypeAndCountByDate(deptId, date);
                Map<String, Object> temp = new HashMap<>(defectMap);
                temp.put("name", name);

                Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
                while (iterator.hasNext()) {
                    Map.Entry<String, Object> next = iterator.next();
                    Map map1 = (Map) next.getValue();
                    temp.computeIfPresent((String) map1.get("status"), (k, v) -> Long.sum((Long) v, (long) map1.get("count")));
                }
                return temp;
            },Map.class));

            futureList.add(future);
        }

        List<Object> list = futureList.stream().map(CompletableFuture::join) // 获取任务执行结果
                .collect(Collectors.toList());
        return Response.success(list);
    }

    @TaskAnnotation("getPatrolCountByDate")
    @Override
    public Response getPatrolCountByDate(SessionFactory factory, String date) {
        ExecutorService executorService = new ThreadPoolExecutor(2, 5, 60, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10));


        List<String> orgDept = getOrgs(factory);
        Map<String, List<String>> deptMap = recursionGetOrgDept(factory, orgDept);
        List<CompletableFuture> futureList = new ArrayList<>();

        for (Map.Entry<String, List<String>> entry : deptMap.entrySet()) {
            try {
                TimeUnit.MILLISECONDS.sleep(100);
            } catch (InterruptedException e) {
                log.error(e.getMessage(), e);
            }
            CompletableFuture<Map<String, Object>> future = CompletableFuture.supplyAsync(() -> ADOConnection.runTask(ThreadLocalContext.get().getCurrDs(), sessionFactory->{
                YcCockpitMapper mapper = sessionFactory.getMapper(YcCockpitMapper.class);
                Long patrolCount = mapper.getPatrolCount(entry.getValue(), date);
                Long errorCount = mapper.getPatrolErrorCount(entry.getValue(), date);
                Long finishInTimeCount = mapper.getPatrolInTimeFinishCount(entry.getValue(), date);
                Long finishAllCount = mapper.getPatrolAllFinishCount(entry.getValue(), date);
                double result = finishAllCount == 0 ? 0 : ((double) finishInTimeCount / finishAllCount) * 100;
                DecimalFormat decimalFormat = new DecimalFormat("0.00");
                String formattedResult = decimalFormat.format(result);
                Map<String, Object> map = new HashMap<>();
                map.put("patrolCount", patrolCount);
                map.put("errorCount", errorCount);
                map.put("finishCount",formattedResult);
                map.put("name", entry.getKey());
                return map;
            }, Map.class), executorService);

            futureList.add(future);
        }

        executorService.shutdown();
        List<Object> result = futureList.stream().map(CompletableFuture::join).collect(Collectors.toList());
        return Response.success(result);
    }

    @TaskAnnotation("sumOrderTotal")
    @Override
    public Response sumOrderTotal(SessionFactory factory) {
        return Response.success(factory.getMapper(YcCockpitMapper.class).sumOrderTotal());
    }

    @TaskAnnotation("sumTicketTotal")
    @Override
    public Response sumTicketTotal(SessionFactory factory) {
        return Response.success(factory.getMapper(YcCockpitMapper.class).sumTicketTotal());
    }

    @TaskAnnotation("getEquipmentStatus")
    @Override
    public Response getEquipmentStatus(SessionFactory factory, PageQuery pageQuery) {
        PageHelper.startPage(pageQuery.getPage(), pageQuery.getPageSize());
        YcCockpitMapper mapper = factory.getMapper(YcCockpitMapper.class);
        List<EquipmentStatus> equipmentStatusList = mapper.getEquipmentStatus();
        return Response.success(equipmentStatusList);
    }

    @TaskAnnotation("getDefectRate")
    @Override
    public Response getDefectRate(SessionFactory factory, String date) {
        List<String> orgDept = getOrgs(factory);
        Map<String, List<String>> deptMap = recursionGetOrgDept(factory, orgDept);
        List<CompletableFuture> futureList = new ArrayList<>();
        for (Map.Entry<String, List<String>> entry : deptMap.entrySet()) {
            try {
                TimeUnit.MILLISECONDS.sleep(100);
            } catch (InterruptedException e) {
                log.error(e.getMessage(), e);
            }
            CompletableFuture<Map<String, Object>> future = CompletableFuture.supplyAsync(() -> ADOConnection.runTask(ThreadLocalContext.get().getCurrDs(), sessionFactory->{
                YcCockpitMapper mapper = sessionFactory.getMapper(YcCockpitMapper.class);
                String name = entry.getKey();
                List<String> deptList = entry.getValue();
                Integer defectRate = mapper.getDefectRate(deptList, date);
                defectRate = defectRate != null ? defectRate : 0;
                Map<String, Object> temp = new HashMap<>();
                temp.put("defectRate", defectRate);
                temp.put("name", name);
                return temp;
                }, Map.class));
            futureList.add(future);
        }
        List<Object> list = futureList.stream().map(CompletableFuture::join).collect(Collectors.toList());
        return Response.success(list);
    }

    @TaskAnnotation("getDefectInTimeRate")
    @Override
    public Response getDefectInTimeRate(SessionFactory factory, String date) {
        List<String> orgDept = getOrgs(factory);
        Map<String, List<String>> deptMap = recursionGetOrgDept(factory, orgDept);
        List<CompletableFuture> futureList = new ArrayList<>();
        for (Map.Entry<String, List<String>> entry : deptMap.entrySet()) {
            try {
                TimeUnit.MILLISECONDS.sleep(100);
            } catch (InterruptedException e) {
                log.error(e.getMessage(), e);
            }
            CompletableFuture<Map<String, Object>> future = CompletableFuture.supplyAsync(() -> ADOConnection.runTask(ThreadLocalContext.get().getCurrDs(), sessionFactory-> {
                YcCockpitMapper mapper = sessionFactory.getMapper(YcCockpitMapper.class);
                String name = entry.getKey();
                List<String> deptList = entry.getValue();
                Integer defectRate = mapper.getDefectInTimeRate(deptList, date);
                defectRate = defectRate != null ? defectRate : 0;
                Map<String, Object> temp = new HashMap<>();
                temp.put("defectRate", defectRate);
                temp.put("name", name);
                return temp;
            },Map.class));
            futureList.add(future);
        }
        List<Object> list = futureList.stream().map(CompletableFuture::join).collect(Collectors.toList());
        return Response.success(list);
    }

    @TaskAnnotation("getOrderCheckPassRate")
    @Override
    public Response getOrderCheckPassRate(SessionFactory factory, String date) throws InterruptedException {
        List<String> orgDept = getOrgs(factory);
        ConcurrentHashMap<String, List<String>> deptMap = recursionGetOrgDept(factory, orgDept);
        List<CompletableFuture> futureList = new ArrayList<>();
        for (Map.Entry<String, List<String>> entry : deptMap.entrySet()) {
            TimeUnit.MILLISECONDS.sleep(100);
            CompletableFuture<Map<String, Object>> future = CompletableFuture.supplyAsync(() -> ADOConnection.runTask(ThreadLocalContext.get().getCurrDs(), sessionFactory->{
                YcCockpitMapper mapper = sessionFactory.getMapper(YcCockpitMapper.class);
                String name = entry.getKey();
                List<String> deptList = entry.getValue();
                Integer defectRate = mapper.getOrderCheckPassRate(deptList, date);
                defectRate = defectRate != null ? defectRate : 0;
                Map<String, Object> temp = new HashMap<>();
                temp.put("passRate", defectRate);
                temp.put("name", name);
                return temp;
            }, Map.class));
            futureList.add(future);
        }
        List<Object> list = futureList.stream().map(CompletableFuture::join).collect(Collectors.toList());
        return Response.success(list);
    }



    @TaskAnnotation("getTicketCheckPassRate")
    @Override
    public Response getTicketCheckPassRate(SessionFactory factory, String date) throws InterruptedException {
        List<String> orgDept = getOrgs(factory);
        ConcurrentHashMap<String, List<String>> deptMap = recursionGetOrgDept(factory, orgDept);
        List<CompletableFuture> futureList = new ArrayList<>();
        for (Map.Entry<String, List<String>> entry : deptMap.entrySet()) {

            TimeUnit.MILLISECONDS.sleep(100);
            String name = entry.getKey();
            List<String> deptList = entry.getValue();
            // 创建新的局部变量并复制entry的Key和Value
            String entryKey = name;
            List<String> entryValue = new ArrayList<>(deptList);

            CompletableFuture<Map<String, Object>> future = CompletableFuture.supplyAsync(() -> ADOConnection.runTask(ThreadLocalContext.get().getCurrDs(), sessionFactory-> {
                        YcCockpitMapper mapper = sessionFactory.getMapper(YcCockpitMapper.class);
                        Integer defectRate = mapper.getTicketCheckPassRate(date, entryValue); // 使用复制后的date参数
                        defectRate = defectRate != null ? defectRate : 0;
                        Map<String, Object> temp = new HashMap<>();
                        temp.put("passRate", defectRate);
                        temp.put("name", entryKey);
                        return temp;
                }, Map.class));
            futureList.add(future);
        }
        CompletableFuture<Void> allFuture = CompletableFuture.allOf(futureList.toArray(new CompletableFuture[0]));
        allFuture.join(); // 等待所有异步任务完成

        List<Object> resultList = futureList.stream()
                .map(CompletableFuture::join) // 获取每个异步任务的结果
                .collect(Collectors.toList());

        return Response.success(resultList);
    }

    private ConcurrentHashMap<String, List<String>> recursionGetOrgDept(SessionFactory factory, List<String> nameList) {
        String orgDeptJson = redisTemplate.opsForValue().get(REDIS_KEY);
        ConcurrentHashMap<String, List<String>> orgDeptMap;
        if (StringUtils.isBlank(orgDeptJson)) {
            YcCockpitMapper mapper = factory.getMapper(YcCockpitMapper.class);
            List<OrgBean> orgBeans = mapper.queryAllOrg();
            String rootId = mapper.queryRootOrg();
            // 构建组织树
            TreeNodeConfig config = new TreeNodeConfig();
            List<Tree<String>> treeList = TreeUtil.build(orgBeans, rootId, config, (item, tree) -> {
                tree.setId(item.getId());
                tree.setParentId(item.getParent());
                tree.setName(item.getNamePy());
                tree.setWeight(item.getSort());
            });
            // 构建存储结构
            orgDeptMap = new ConcurrentHashMap<>();
            for (String name : nameList) {
                List<String> deptIdList = new ArrayList<>();
                Tree tree = search(treeList, name);
                if (tree != null) {
                    deptIdList.add((String) tree.getId());
                    List<Tree> children = (List<Tree>) tree.getChildren();
                    if (children != null) {
                        children.stream().forEach(x -> {
                            deptIdList.add((String) x.getId());
                        });
                    }
                    orgDeptMap.put(name, deptIdList);
                }
            }
            String jsonStr = JSONUtil.toJsonStr(orgDeptMap);
            redisTemplate.opsForValue().set(REDIS_KEY, jsonStr, REDIS_EXPIRY_HOURS, TimeUnit.HOURS);
        } else {
            orgDeptMap = JSONUtil.parseObj(orgDeptJson).toBean(ConcurrentHashMap.class);
        }
        return orgDeptMap;
    }

    public Tree search(List<Tree<String>> treeList, String targetName) {
        if (CollectionUtils.isEmpty(treeList)) {
            return null;
        }
        for (Tree<String> tree : treeList) {
            if (targetName.equals(tree.getName())) {
                return tree;
            }
            if (tree.getChildren() != null && !tree.getChildren().isEmpty()) {
                Tree treeNode = search(tree.getChildren(), targetName);
                // 如果找到了节点立马返回
                if (treeNode != null) {
                    return treeNode;
                }
            }
        }
        return null;
    }


    public List<String> getOrgs(SessionFactory factory) {
        factory.setDbEnv("_default");
        String classifyId = "workorderManagement";
        String code = "order_stat_dept";
        SysDataDict sysDataDict = sysDataDictService.getByClassifyIdAndCode(factory, classifyId, code);
        List<SysDataDictDetail> sysDataDictDetailList = sysDataDict.getSysDataDictDetailList();
        List<String> orgNameList = sysDataDictDetailList.stream().map(SysDataDictDetail::getKey).collect(Collectors.toList());
        log.info("orgNameList = {}", orgNameList);

        return orgNameList;
    }
}
